﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Irony.Parsing;

namespace HumanWorkflow.TextualDslParser.IronyParser
{
    [Language("HWDL", "1.0", "Human Workflow Definition Language")]
    public class HwdlGrammar : Grammar
    {
        public HwdlGrammar()
            : base(false) //Csd is case insensitive
        {
            InitializeGrammar();
        }

        void InitializeGrammar()
        {
            #region Terminals

            var comment = new CommentTerminal("comment", "/*", "*/");
            var lineComment = new CommentTerminal("line_comment", "//", "\n", "\r\n");
            var definitionComment = new CommentTerminal("definitionComment", "#", "#");

            NonGrammarTerminals.Add(comment);
            NonGrammarTerminals.Add(lineComment);

            var it_workflow_def = new IdentifierTerminal("it_workflow_def");
            var it_role_def = new IdentifierTerminal("it_role_def");
            var it_base_step_def = new IdentifierTerminal("it_base_step_def");
            var it_manual_step_def = new IdentifierTerminal("it_manual_step_def");
            var it_done_by_role_ref = new IdentifierTerminal("it_done_by_role_ref");
            var it_final_step_def = new IdentifierTerminal("it_final_step_def");
            var it_transition_def = new IdentifierTerminal("it_transition_def");
            var it_transition_target_step_ref = new IdentifierTerminal("it_transition_target_step_ref");

            var kt_workflow = ToTerm("workflow");

            var kt_roles = ToTerm("roles");

            var kt_initial = ToTerm("initial");
            var kt_decision = ToTerm("decision");
            var kt_manual = ToTerm("manual");
            var kt_automatic = ToTerm("automatic");
            var kt_final = ToTerm("final");

            var kt_goesto = ToTerm("goesto");
            var kt_when = ToTerm("when");
            var kt_doneby = ToTerm("doneby");

            // for keyword colorization
            MarkReservedWords("workflow", "roles", "initial", "decision", "manual", "automatic", "final", "goesto", "when", "doneby");
            RegisterBracePair("{", "}");

            #endregion

            #region Non-terminals

            var HUMAN_WORKFLOW = new NonTerminal("HUMAN_WORKFLOW");
            var WORKFLOW_BODY = new NonTerminal("WORKFLOW_BODY");
            var WORKFLOW_BLOCK = new NonTerminal("WORKFLOW_BLOCK");

            var ROLE_LIST_SECTION = new NonTerminal("ROLE_LIST_SECTION");
            var ROLE_LIST_BLOCK = new NonTerminal("ROLE_LIST_BLOCK");
            var ROLE_LIST = new NonTerminal("ROLE_LIST");
            var ROLE = new NonTerminal("ROLE");

            var STEP_LIST = new NonTerminal("STEP_LIST");
            var STEP = new NonTerminal("STEP");

            var BASE_STEP = new NonTerminal("BASE_STEP");
            var BASE_STEP_HEADER = new NonTerminal("BASE_STEP_HEADER");
            var BASE_STEP_TYPE = new NonTerminal("BASE_STEP_TYPE");
            var BASE_STEP_BLOCK = new NonTerminal("BASE_STEP_BLOCK");

            var MANUAL_STEP = new NonTerminal("MANUAL_STEP");
            var MANUAL_STEP_HEADER = new NonTerminal("MANUAL_STEP_HEADER");
            var MANUAL_STEP_TYPE = new NonTerminal("MANUAL_STEP_TYPE");
            var MANUAL_STEP_BLOCK = new NonTerminal("MANUAL_STEP_BLOCK");
            var DONE_BY = new NonTerminal("DONE_BY");

            var FINAL_STEP = new NonTerminal("FINAL_STEP");

            var TRANSITION_LIST = new NonTerminal("TRANSITION_LIST");
            var TRANSITION = new NonTerminal("TRANSITION");
            var TRANSITION_TARGET = new NonTerminal("TRANSITION_TARGET");
            var TRANSITION_EVENT = new NonTerminal("TRANSITION_EVENT");

            var OPT_DEFINITION = new NonTerminal("OPT_DEFINITION");
            MarkTransient(OPT_DEFINITION);

            #endregion

            #region Rules

            this.Root = HUMAN_WORKFLOW;

            HUMAN_WORKFLOW.Rule = kt_workflow + it_workflow_def + WORKFLOW_BLOCK;
            WORKFLOW_BLOCK.Rule = ToTerm("{") + WORKFLOW_BODY + "}";
            WORKFLOW_BODY.Rule = ROLE_LIST_SECTION + STEP_LIST;

            ROLE_LIST_SECTION.Rule = kt_roles + ROLE_LIST_BLOCK;
            ROLE_LIST_BLOCK.Rule = ToTerm("{") + ROLE_LIST + "}";
            ROLE_LIST.Rule = MakePlusRule(ROLE_LIST, ToTerm(","), ROLE);
            ROLE.Rule = OPT_DEFINITION + it_role_def;

            STEP_LIST.Rule = MakePlusRule(STEP_LIST, STEP);
            STEP.Rule = BASE_STEP | MANUAL_STEP | FINAL_STEP;

            BASE_STEP.Rule = BASE_STEP_HEADER + BASE_STEP_BLOCK;
            BASE_STEP_HEADER.Rule = OPT_DEFINITION + BASE_STEP_TYPE + it_base_step_def;
            BASE_STEP_TYPE.Rule = kt_initial | kt_decision | kt_automatic;
            BASE_STEP_BLOCK.Rule = ToTerm("{") + TRANSITION_LIST + "}";

            TRANSITION_LIST.Rule = MakePlusRule(TRANSITION_LIST, TRANSITION);
            TRANSITION.Rule = OPT_DEFINITION + TRANSITION_TARGET + TRANSITION_EVENT + ";";
            TRANSITION_TARGET.Rule = kt_goesto + it_transition_target_step_ref;
            TRANSITION_EVENT.Rule = kt_when + it_transition_def;

            MANUAL_STEP.Rule = MANUAL_STEP_HEADER + MANUAL_STEP_BLOCK;
            MANUAL_STEP_HEADER.Rule = OPT_DEFINITION + MANUAL_STEP_TYPE + it_manual_step_def;
            MANUAL_STEP_TYPE.Rule = kt_manual;
            MANUAL_STEP_BLOCK.Rule = ToTerm("{") + TRANSITION_LIST + DONE_BY + "}";
            DONE_BY.Rule = kt_doneby + it_done_by_role_ref + ";";

            FINAL_STEP.Rule = OPT_DEFINITION + kt_final + it_final_step_def + ";";
            OPT_DEFINITION.Rule = Empty | definitionComment;
 
            #endregion        
        }

       
    }
}
